<?php
declare(strict_types=1);
/**
 * Author: Traveler
 * Time  : 2021/8/31 14:30
 */

namespace sunshine\utils;


/**
 * Crypt加解密类
 *
 * @package sunshine\utils
 */
class Crypt
{
    /**
     * 加密模式
     *
     * @var string
     */
    private $mode;

    /**
     * 加密密钥
     *
     * @var string
     */
    private $key;

    /**
     * 加密初始化向量
     *
     * @var string
     */
    private $iv;

    /**
     * 加密选项
     *
     * @var int
     */
    private $options;

    /**
     * 使用AEAD密码模(GCM或CCM)时传引用的验证标签
     *
     * @var string
     */
    private $tag;

    /**
     * 附加的验证数据
     *
     * @var string
     */
    private $aad;

    /**
     * 验证tag的长度
     *
     * @var int
     */
    private $length;

    /**
     * 是否AEAD密码模式(GCM或CCM)
     *
     * @var bool
     */
    private $isAEAD = false;

    /**
     * 构造方法
     *
     * @param string      $mode    加密模式
     * @param string      $key     加密密钥
     * @param string      $iv      加密初始化向量
     * @param int         $options 加密选项
     * @param string|null $tag     使用AEAD密码模式(GCM或CCM)时传引用的验证标签
     * @param string      $aad     附加的验证数据
     * @param int         $length  验证tag的长度
     */
    public function __construct(string $mode,
                                string $key,
                                string $iv = "",
                                int $options = 0,
                                &$tag = null,
                                string $aad = "",
                                int $length = 16)
    {
        $this->mode    = $mode;
        $this->key     = $key;
        $this->iv      = $iv;
        $this->options = $options;
        $this->tag     = &$tag;
        $this->aad     = $aad;
        $this->length  = $length;
    }

    /**
     * 加密方法
     *
     * @param string $data 待加密的明文数据
     * @return string
     */
    public function encrypt(string $data): string
    {
        if ($this->isAEAD) {
            $result = openssl_encrypt(
                $data,
                $this->mode,
                $this->key,
                $this->options,
                $this->iv,
                $this->tag,
                $this->aad,
                $this->length
            );
        } else {
            $result = openssl_encrypt(
                $data,
                $this->mode,
                $this->key,
                $this->options,
                $this->iv
            );
        }

        return $result ?: '';
    }

    /**
     * 解密方法
     *
     * @param string $data 待解密的密文数据
     * @return string
     */
    public function decrypt(string $data): string
    {
        if ($this->isAEAD) {
            $result = openssl_decrypt(
                $data,
                $this->mode,
                $this->key,
                $this->options,
                $this->iv,
                $this->tag,
                $this->aad
            );
        } else {
            $result = openssl_decrypt(
                $data,
                $this->mode,
                $this->key,
                $this->options,
                $this->iv
            );
        }

        return $result ?: '';
    }

    /**
     * 设置为AEAD密码模式(GCM或CCM)
     *
     * @return $this
     */
    public function isAEAD(): Crypt
    {
        $this->isAEAD = true;

        return $this;
    }
}